#include "CDFize.h"
#include "CSettings.h"

CDFize::CDFize()
	: IEventReceiver(),
		Device(0), HqImage(0), HqTexture(0), Camera(0), CameraAnimator(0),
		Region(0), ShowCollisionData(false), GuiTileType(0), GuiVegType(0),
		GuiMaterial(0), CameraFollowNode(0), DfHack(0)
{
}

CDFize::~CDFize()
{
/*	std::vector<SNode*>::iterator it = Creatures.begin();
	for(; it != Creatures.end(); ++it)
		delete *it;
	Creatures.clear();*/

	if(Device)
	{
		Device->closeDevice();
		Device->drop();
	}

	if(DfHack)
		DfHack->Detach();
}

bool CDFize::init()
{
	if(!createIrrlichtDevice())
		return false;
	createGui();

	if(!initDfHack())
		return false;

	DFHack::ContextManager DFMgr("Memory.xml");
    try
    {
        DfHack = DFMgr.getSingleContext();
        DfHack->Attach();
    }
    catch (...)
    {
		log("DFHack", "Failed to initialize");
        return false;
    }
	log("DFHack", "Initialized");
	
	DFHack::Maps *Maps = DfHack->getMaps();

	//creatures = DfHack->getCreatures();

	Maps->Start();

	uint32_t mapx, mapy, mapz;
	Maps->getSize(mapx, mapy, mapz);
	MapX = mapx;
	MapY = mapy;
	MapZ = mapz;

	Region = new CRegionSceneNode(Device->getSceneManager()->getRootSceneNode(), Device->getSceneManager(), -1, vector3di(mapx, mapz, mapy));
	Region->drop();

	// Read resources
	log("DFize", "Loading resources");
	std::vector<std::wstring> files;
	getFileList(L"data/resources/*.*", files);
	std::vector<std::wstring>::iterator it = files.begin();
	for(; it != files.end(); ++it)
	{
		stringw name((*it).c_str());
		s32 i = name.findLastChar(L".", 1);
		std::string cname = stringc(stringw((*it).c_str())).subString(0, i).c_str();

		CSettings *settings = new CSettings((std::string("data/resources/") + stringc(name).c_str()), 0, "");
		irr::core::list<SResource*> resx;
		settings->readResources(Device->getSceneManager(), resx);

		irr::core::list<SResource*>::Iterator it = resx.begin();
		for(; it != resx.end(); ++it)
			Region->addResource(*it);
		delete settings;
	}

	video::IGPUProgrammingServices* gpu = Device->getVideoDriver()->getGPUProgrammingServices();
	if(gpu)
	{
		log("DFize", "Loading shaders");
		std::vector<std::wstring> files;
		getFileList(L"data/shaders/*.*", files);
		std::vector<std::wstring>::iterator it = files.begin();
		for(; it != files.end(); ++it)
		{
			stringw name((*it).c_str());
			s32 i = name.findLastChar(L".", 1);

			std::string cname = stringc(name).subString(0, i).c_str();
			if(Region->getShaderMaterial(cname.c_str()))
				continue;

			std::string vert = std::string("data/shaders/") + cname + ".vert";
			std::string frag = std::string("data/shaders/") + cname + ".frag";

			const c8 *vertfile = vert.c_str();
			const c8 *fragfile = frag.c_str();		

			if(!CSettings::fileExists(vertfile))
				vertfile = 0;
			if(!CSettings::fileExists(fragfile))
				fragfile = 0;

			s32 type = gpu->addHighLevelShaderMaterialFromFiles(vertfile, "main", EVST_VS_1_1, fragfile, "main", EPST_PS_1_1);
			Region->addShaderMaterial(cname, type);
		}
	}

	int pid = DfHack->getProcess()->getPID();

	std::wstring folder = L"";

	HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); 
	
	std::wstring dwarf_fortress_folder;

	if(processHandle != NULL)
	{
		TCHAR exe_path[MAX_PATH] = {0};
		if(GetModuleFileNameEx(processHandle, NULL, exe_path, sizeof(exe_path)) == 0)
		{
			log("DFize", "Failed to get Dwarf Fortress directory");
		}
		else
		{
			std::wstring folder = std::wstring(exe_path);
			int fpos = folder.find_last_of('\\');
			if(fpos != std::wstring::npos)
				folder = folder.substr(0, fpos+1);
			dwarf_fortress_folder = folder;
		}
		CloseHandle(processHandle);
	}

	Camera->setPosition(vector3df(mapx * 8 - 1, (f32)mapz, (f32)mapy * 8) + vector3df(0.25f,0.25f,0.25f));
	Camera->setTarget(vector3df(mapx * 8 - 1, (f32)mapz, (f32)mapy * 8 + 1));

	IVideoDriver *video = Device->getVideoDriver();

	std::map<std::string, DFHack::t_matgloss> matgloss_inorganic;
	std::map<std::string, DFHack::t_matgloss> matgloss_plant;

	if(!dwarf_fortress_folder.empty())
	{
		log("DFize", "Reading inorganic material colors from raw/objects/");
		std::vector<std::wstring> files;
		getFileList((dwarf_fortress_folder + L"raw\\objects\\inorganic_*.txt").c_str(), files);
		std::vector<std::wstring>::iterator it = files.begin();
		for(; it != files.end(); ++it)
		{
			std::string data = "";
			std::wstring file = dwarf_fortress_folder + L"raw\\objects\\" + (*it).c_str();
			CSettings::readDfMaterials(stringc(file.c_str()).c_str(), "INORGANIC", matgloss_inorganic);
		}

		log("DFize", "Reading plant material colors from raw/objects/");

		files.clear();
		getFileList((dwarf_fortress_folder + L"raw\\objects\\plant_*.txt").c_str(), files);
		it = files.begin();
		for(; it != files.end(); ++it)
		{
			std::string data = "";
			std::wstring file = dwarf_fortress_folder;
			file.append(L"raw\\objects\\");
			file.append(*it);
			CSettings::readDfMaterials(stringc(file.c_str()).c_str(), "PLANT", matgloss_plant);
		}
	}

	log("DFize", "Reading materials");

	DFHack::Materials *Materials = DfHack->getMaterials();
	Materials->Start();
	Materials->ReadAllMaterials();

	u32 mi = 1;
	std::vector<DFHack::t_matgloss>::iterator mit = Materials->inorganic.begin();
	for(; mit != Materials->inorganic.end(); ++mit)
	{
		std::map<std::string, DFHack::t_matgloss>::iterator it = matgloss_inorganic.find((*mit).id);
		DFHack::t_matgloss mg = (*mit);
		if(it != matgloss_inorganic.end())
			mg = (*it).second;
		Region->AddInorganicMaterial(new SBasicMaterial(Region->readMaterial((*mit).id), video, mi, (*mit).id, mg));
		mi++;
	}

	/*std::vector<DFHack::t_matglossOther>::iterator omit = Materials->other.begin();
	for(; omit != Materials->other.end(); ++omit)
	{
		//printf("%d: %s\n", mi, (*omit).rawname);
		mi++;
	}*/

	mit = Materials->plant.begin();
	for(; mit != Materials->plant.end(); ++mit)
	{
		//printf("%d: %s %s (%d,%d,%d)\n", mi, (*mit).id, (*mit).name, (*mit).fore, (*mit).back, (*mit).bright);
		std::map<std::string, DFHack::t_matgloss>::iterator it = matgloss_plant.find((*mit).id);
		DFHack::t_matgloss mg = (*mit);
		if(it != matgloss_plant.end())
			mg = (*it).second;
		//printf("%d: %s %s (%d,%d,%d)\n", mi, (*mit).id, (*mit).name, mg.fore, mg.back, mg.bright);
		Region->AddPlantMaterial(new SBasicMaterial(Region->readMaterial((*mit).id), video, mi, (*mit).id, mg));
		mi++;
	}

	/*mi = 1;
	mit = Materials->tree.begin();
	for(; mit != Materials->tree.end(); ++mit)
	{
		//printf("%d: %s %s (%d,%d,%d)\n", mi, (*mit).id, (*mit).name, (*mit).fore, (*mit).back, (*mit).bright);
		mi++;
	}*/

	//mi = 1;
	/*mit = Materials->organic.begin();
	for(; mit != Materials->organic.end(); ++mit)
	{
		//printf("%d: %s %s (%d,%d,%d)\n", mi, (*mit).id, (*mit).name, (*mit).fore, (*mit).back, (*mit).bright);
		mi++;
	}*/

	Materials->Finish();

	log("DFize", "Importing tiles");

	std::vector<std::vector<uint16_t, std::allocator<char16_t>>> geology;
	Maps->ReadGeology(geology);
	for(uint32_t iy=0; iy < mapy; iy++)
	{
		for(uint32_t ix=0; ix < mapx; ix++)
		{
			bool first = true;
			for(int32_t iz=mapz-1; iz >= 0; iz--)
			{
				if(!Maps->isValidBlock(ix, iy, iz))
					continue;

				DFHack::mapblock40d mapblock;

				if(Maps->ReadBlock40d(ix, iy, iz, &mapblock))
				{
					CBlockSceneNode *blockscenenode = Region->getBlock(ix, iz, iy);
					for(uint32_t xi = 0 ; xi < 16 ; xi++)
					{
						for(uint32_t yi = 0 ; yi < 16 ; yi++)
						{
							if(blockscenenode != 0)
							{
								u16 tt = mapblock.tiletypes[xi][yi];
								if(DFHack::isWallTerrain(tt) || DFHack::isFloorTerrain(tt) || DFHack::isRampTerrain(tt) || DFHack::isStairTerrain(tt))
								{
									u32 geolayer = mapblock.designation[xi][yi].bits.geolayer_index;
									u32 biome = mapblock.designation[xi][yi].bits.biome;
									u32 index = geology[mapblock.biome_indices[biome]][geolayer];

									blockscenenode->addTile(vector3df((f32)xi, 0, (f32)yi), tt, Region->getInorganicMaterial(index));
								}
							}
						}
					}
				}
			}
		}
	}
	Maps->Finish();

	DFHack::Constructions *Constructions = DfHack->getConstructions();
	u32 constructioncount;
	Constructions->Start(constructioncount);
	for(u32 ci = 0; ci < constructioncount; ci++)
	{
		DFHack::t_construction constr;
		if(Constructions->Read(ci, constr))
		{
			SBasicMaterial *m = Region->getMaterial(constr.mat_idx, constr.mat_type);
			CBlockSceneNode *block = Region->getBlock(constr.x / 16, constr.z, constr.y / 16);
			if(block)
			{
				CTile *tile = block->getTile(15 - constr.x % 16, constr.y % 16);
				if(tile)
				{
					tile->setMaterial(m);
				}
				else
					printf("notile %d %d %d\n", constr.x % 16, constr.z, constr.y % 16);
			}
			else
				printf("noblock\n");
		
	//		stringw s(stringw(m ? m->Name.c_str() : "") + " " + stringw(constr.form) + " " + stringw(constr.mat_type) + " " + stringw(mapx * 16 - (constr.x) - 1) + "," + stringw(constr.z) + "," + stringw(constr.y));
	//		ISceneNode *ac = smgr->addCubeSceneNode(0.25f, 0, -1, vector3df(mapx * 16 - ((f32)constr.x) - 1, constr.z, (f32)constr.y) + vector3df(0.5f, 0.0f, 0.5f), vector3df(0,0,0), vector3df(1, 1, 1));
	//		smgr->addBillboardTextSceneNode(0, s.c_str(), ac, dimension2df(0.5f, 0.25f), vector3df(0, 0.25f, 0));
		}
	}
	Constructions->Finish();

	DFHack::Buildings *Buildings = DfHack->getBuildings();
	u32 building_count = 0;
	Buildings->Start(building_count);

	std::map<u32, std::string> custom_workshops;
	Buildings->ReadCustomWorkshopTypes(custom_workshops);

	for(u32 i = 0; i < building_count; i++)
	{
		DFHack::t_building building;
		if(Buildings->Read(i, building))
		{
			CBlockSceneNode *blockscenenode = Region->getBlock(building.x1 / 16, building.z, building.y1 / 16);
			stringw s = /*stringw(building.x1) + "," + stringw(building.y1) + "/" + stringw(building.x2) + "," + stringw(building.y2) +*/ stringw("type:") + stringw(building.type) + " material:" + stringw(building.material.index) + " mattype:" + stringw(building.material.type);

			s32 ci = Buildings->GetCustomWorkshopType(building);
			if(ci >= 0)
				s = stringw(custom_workshops[ci].c_str());

			blockscenenode->addBuilding(vector3df((f32)(building.x1 % 16), 0, (f32)(building.y1 % 16)), building.type, Region->getMaterial(building.material.index, building.material.type));//region->getInorganicMaterial(building.material.index));

//			vector3df pos = vector3df(mapx * 16 - ((f32)building.x1) - 1, (f32)building.z, (f32)building.y1) + vector3df(0.5f, 0.25f, 0.5f);
//			ISceneNode *ac = smgr->addCubeSceneNode(0.25f, 0, -1, pos/*blockscenenode->getAbsolutePosition() + vector3df((f32)(building.x1 % 16 - 1) + 0.25f, 0.25f, (f32)(building.y1 % 16) + 0.25f)*/);
//			smgr->addBillboardTextSceneNode(0, s.c_str(), ac, dimension2df(0.75f, 0.25f), vector3df(0, 0.25f, 0));
		}
	}
	Buildings->Finish();


	log("DFize", "Importing creatures");
	DFHack::Creatures *creatures = DfHack->getCreatures();

    DFHack::Translation * Tran = DfHack->getTranslation();

    uint32_t numCreatures;
    if(!creatures->Start(numCreatures))
    {
       log("DFize", "Failed to import creatures");
    }

    //mem = DF->getMemoryInfo();

    if(!Tran->Start())
    {
        log("DFize", "Failed to get translation table");
    }

	uint32_t i = 0;
	DFHack::t_creature temp;
	bool first = true;
	bool firstdwarf = true;

	ISceneManager *smgr = Device->getSceneManager();

	while(i < numCreatures)
    {
        creatures->ReadCreature(i,temp);

		if(temp.flags1.bits.dead == 0)
        {
			uint32_t color = 0;
			if(temp.race < Materials->raceEx.size())
			{
				Materials->raceEx[temp.race].tilecolor.fore;
				float r = Materials->color[color].r;
				float v = Materials->color[color].v;
				float b = Materials->color[color].b;
			}

			wchar_t name[255] = L"";
			std::string transName = Tran->TranslateName(temp.name,false);
			temp.name.first_name[0] = toupper(temp.name.first_name[0]);
			transName = std::string(temp.name.first_name) + " " + transName;
			mbstowcs(name, transName.c_str(), 255);

			IMeshSceneNode *cube = smgr->addCubeSceneNode(0.25f, 0, temp.origin, vector3df(mapx * 16 - ((f32)temp.x) - 1, temp.z, (f32)temp.y) + vector3df(0.5f, 0.2f, 0.5f), vector3df(0,0,0), vector3df(1, 1, 1));
			if(name[0] != 0)
			{
				IBillboardTextSceneNode *text = smgr->addBillboardTextSceneNode(0, name, cube, dimension2d<f32>(0.75f, 0.25f), vector3df(0, 0.2f, 0));
//				scene::ITextSceneNode *text = smgr->addTextSceneNode(gui->getBuiltInFont(), name, SColor(100, 255, 255, 255), cube, vector3df(0, 0.2f, 0));
	//			text->setScale(vector3df(1.5f, 1.5f, 1.5f));
			}

			cube->setMaterialType(video::EMT_SOLID);

		/*	if(creatures->GetDwarfRaceIndex() == temp.race)
			{
				u32 i = CreatureList->addItem(name);

				SNode *node = new SNode;
				node->Creature = temp;
				node->Node = cube;
				Creatures.push_back(node);
				//dwarves.push_back(cube);
				if(firstdwarf)
				{
					firstdwarf = false;
					Camera->setPosition(vector3df(mapx * 16 - ((f32)temp.x) - 1, (f32)temp.z, (f32)temp.y) + vector3df(0.25f,0.25f,0.25f));
					Camera->setTarget(vector3df(mapx * 16 - ((f32)temp.x) - 1, (f32)temp.z, (f32)temp.y + 1));
				}
			}*/
        }
		i++;
    }

	creatures->Finish();

	DfHack->Detach();

	
	CollisionAnimator = smgr->createCollisionResponseAnimator(Region->getTriangleSelector(), Camera, vector3df(0.15f, 0.2f, 0.15f), vector3df(0, -1.0f, 0));
	Camera->addAnimator(CollisionAnimator);
	CameraAnimator->setVerticalMovement(false);

	return true;
}

bool CDFize::OnEvent(const SEvent& event)
{
	if(event.EventType == EET_GUI_EVENT)
	{
		switch(event.GUIEvent.EventType)
		{
		case EGET_COMBO_BOX_CHANGED:
			{
				IGUIComboBox *box = (IGUIComboBox*)event.GUIEvent.Caller;
				s32 s = box->getSelected();
				if(s != -1)
					Camera->setFarValue((f32)box->getItemData(s));
				//	region->setDrawDistance((f32)box->getItemData(s));
			}
			break;
		case EGET_CHECKBOX_CHANGED:
			{
				IGUICheckBox *box = (IGUICheckBox*)event.GUIEvent.Caller;
				switch(event.GUIEvent.Caller->getID())
				{
				case 1:
					Region->showTerrain(box->isChecked());
					break;
				case 2:
					ShowCollisionData = ((IGUICheckBox*)event.GUIEvent.Caller)->isChecked();
					break;
				case 3:
					Region->setWireframe(((IGUICheckBox*)event.GUIEvent.Caller)->isChecked());
					break;
				case 4:
					if(box->isChecked())
					{
						CameraAnimator->setVerticalMovement(false);
						CollisionAnimator->setTargetNode(Camera);
						CollisionAnimator->setAnimateTarget(true);
					}
					else
					{
						CameraAnimator->setVerticalMovement(true);
						CollisionAnimator->setAnimateTarget(false);
					}
					break;
				case 5:
			//		ShowAdjacentTiles = box->isChecked();
					break;
				case 6:
			//		ShowCornerTiles = box->isChecked();
					break;
				case 7:
					Region->setUseBatching(box->isChecked());
					break;
				}
			}
			break;
		case EGET_LISTBOX_CHANGED:
			{
				/*IGUIListBox *list = (IGUIListBox*)event.GUIEvent.Caller;
				s32 id = list->getSelected();
				if(id != -1)
				{
					ISceneNode *node = Creatures[id];
					if(node != 0)
					{
						CameraFollowNode = node;
						Camera->setPosition(node->getAbsolutePosition());
						if(CollisionAnimator) CollisionAnimator->setTargetNode(Camera);
					}
				}*/
			}
			break;
		}
	}
	else if(event.EventType == EET_KEY_INPUT_EVENT)
	{
	//	keyinput[event.KeyInput.Key] = event.KeyInput.PressedDown;
		if(event.KeyInput.PressedDown)
		{
			if(event.KeyInput.Key == KEY_LSHIFT)
			{
				if(CameraAnimator)
					CameraAnimator->setMoveSpeed(0.02f);
				return true;
			}
			/*if(event.KeyInput.Key == KEY_SPACE)
			{
				if(cam->isInputReceiverEnabled())
					cam->setInputReceiverEnabled(false);
				else
				{
					cursor->setPosition(0.5f, 0.5f);
					cam->setInputReceiverEnabled(true);
				}
			}*/
		}
		else
		{
			if(event.KeyInput.Key == KEY_LSHIFT)
			{
				if(CameraAnimator)
					CameraAnimator->setMoveSpeed(0.002f);
				return true;
			}
			else if(event.KeyInput.Key == KEY_SPACE)
			{
				if(Camera->isInputReceiverEnabled())
				{
					Camera->setInputReceiverEnabled(false);
					CollisionAnimator->setGravity(vector3df(0,0,0));
				}
				else
				{
					Device->getCursorControl()->setPosition(0.5f, 0.5f);
					Camera->setInputReceiverEnabled(true);
					CameraFollowNode = 0;
					CollisionAnimator->setGravity(vector3df(0,-1.0f,0));
				}
			}
			else if(event.KeyInput.Key == KEY_F2)
			{
				IVideoDriver *video = Device->getVideoDriver();
				video->beginScene();
				video->setRenderTarget(HqTexture);
				Region->setHq(true);
			//	f32 dd = region->getDrawDistance();
			//	region->setDrawDistance(5000);
				f32 dd = Camera->getFarValue();
				Camera->setFarValue(500);
				Region->setForceRecalculation(true);
				Region->preRender();
//					region->render();
				Device->getSceneManager()->drawAll();
			//	region->setDrawDistance(dd);
				Camera->setFarValue(dd);
				Region->setHq(false);
				Region->setForceRecalculation(false);
				video->setRenderTarget(0);
				video->endScene();
				Region->preRender();

				IImage *hq_image = video->createImage(HqTexture, vector2d<s32>(0,0), HqTexture->getSize());
				video->writeImageToFile(hq_image, stringc("screenshot_") + stringc(Device->getTimer()->getRealTime()) + ".jpg");
				hq_image->drop();

				HqImage->setImage(HqTexture);
				HqImage->setScaleImage(true);
			}
		}
	}
	return false;
}

void CDFize::run()
{
	ITimer *timer = Device->getTimer();
	unsigned int lastupdate = timer->getRealTime();

	ISceneManager *smgr = Device->getSceneManager();
	IVideoDriver *video = Device->getVideoDriver();
	IGUIEnvironment *gui = Device->getGUIEnvironment();

	ICursorControl *cursor = Device->getCursorControl();

	while(Device->run())
	{
		ISceneCollisionManager *colman = smgr->getSceneCollisionManager();
		
		vector3df outpoint;
		triangle3df outtri;
		CTile *tile = (CTile*)colman->getSceneNodeAndCollisionPointFromRay(colman->getRayFromScreenCoordinates(cursor->getPosition()), outpoint, outtri, 0, Region->getDummyNode());

		if(CameraFollowNode)
		{
			Camera->setInputReceiverEnabled(false);
			vector3df target = CameraFollowNode->getAbsolutePosition();
			Camera->setPosition(target - vector3df(0,0,0.5));
			Camera->setTarget(target);
		}

		wchar_t caption[255];
		vector3di pos = tile ? tile->getGlobalPosition() : vector3di(0,0,0);

		SBasicMaterial *mate = 0;
		wchar_t matestring[255] = {0};
		if(tile)
		{
			mbstowcs(matestring, ("Resource: " + tile->Resource->Name).c_str(), 255);
			GuiVegType->setText(matestring);

			matestring[0] = 0;
			mate = tile->getMaterial();
			if(mate)
			{
				char bb[100];
				sprintf_s(bb, 100, " %d %d %d %d", mate->Material.MaterialType, mate->MatGloss.fore, mate->MatGloss.bright, mate->MatGloss.back);
				mbstowcs(matestring, ("Material type: " + mate->Name + std::string(bb)).c_str(), 255);
			}
			GuiMaterial->setText(matestring);
			
			matestring[0] = 0;
			swprintf_s(matestring, L"Position: %d %d %d", pos.X, pos.Y, pos.Z);
			GuiTileType->setText(matestring);
		}

		#ifdef WIN32
		swprintf_s(caption, 255, L"DFize - %d fps", video->getFPS());
		#else
		swprintf(caption, 255, L"DFize - %d fps", video->getFPS());
		#endif
		Device->setWindowCaption(caption);

		video->beginScene();
		smgr->drawAll();

		if(ShowCollisionData)
		{
			ITriangleSelector *ts = Region->getTriangleSelector();
			s32 tc = ts->getTriangleCount();
			if(tc > 0)
			{
				matrix4 m = Region->getAbsoluteTransformation();
				video->setTransform(ETS_WORLD, m);
				SMaterial mat = IdentityMaterial;
				mat.EmissiveColor = SColor(50, 0, 0, 100);
				mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
				video->setMaterial(mat);
				triangle3df *t = new triangle3df[tc];
				s32 c;
				ts->getTriangles(t, tc, c);
				for(s32 i = 0; i < c; i++)
					video->draw3DTriangle(t[i]);
				delete [] t;
			}
		}

		gui->drawAll();

		video->endScene();

/*		unsigned int thistime = timer->getRealTime();
		if(thistime - lastupdate > CreatureUpdateInterval)
		{
			lastupdate = thistime;

			for(unsigned int i=0; i < Creatures.size(); i++)
			{
				//SNode node = nodes[i];
				DFHack::t_creature temp;
				try
				{
				//	mem->getJob
					//node.Creature.current_job
					Creatures[i]->LastPosition = Creatures[i]->Node->getPosition();
					creatures->UpdateCreature(Creatures[i]->Creature.origin, temp);
					//nodes[i].Node->setPosition(vector3df(temp.x, temp.z, temp.y) + vector3df(0.5f, 0.5f, 0.5f));
					Creatures[i]->Node->removeAnimators();
					ISceneNodeAnimator *anim = smgr->createFlyStraightAnimator(Creatures[i]->Node->getPosition(), vector3df(MapX * 16 - ((f32)temp.x) - 1, temp.z, temp.y) + vector3df(0.5f, 0.2f, 0.5f), CreatureUpdateInterval * 2);
					Creatures[i]->Node->addAnimator(anim);
					anim->drop();
				}
				catch(...)
				{
					log("DFize", "Creature died or disappeared");
					Creatures[i]->Node->remove();
					Creatures.erase(Creatures.begin() + i);
					i--;
				}

			}
		}*/

 		//dev->yield();
	}

	//creatures->Finish();
}

void CDFize::log(const char *a, const char *b)
{
	if(b)
		printf("%s: %s\n", a, b);
	else
		printf("%s\n", a);
}

void CDFize::getFileList(const wchar_t *pattern, std::vector<std::wstring> &files)
{
	WIN32_FIND_DATA FindFileData;
	HANDLE hFind;
	hFind = FindFirstFile(pattern, &FindFileData);
	if(hFind != INVALID_HANDLE_VALUE)
	{
		do
		{
			std::wstring file(FindFileData.cFileName);
			if(file[0] == '.')
				continue;
			files.push_back(file);
		}
		while(FindNextFile(hFind, &FindFileData));
		FindClose(hFind);
	}
}

bool CDFize::createIrrlichtDevice()
{
	CSettings *settingsreader = new CSettings("settings.txt", 0, "");
	SSettings settings = settingsreader->readSettings();
	delete settingsreader;

	//for(int i=0; i < KEY_KEY_CODES_COUNT; i++) keyinput[i] = false;

	irr::SIrrlichtCreationParameters cp;
	cp.DriverType = EDT_OPENGL;
	cp.WindowSize = settings.Resolution;
	cp.Fullscreen = settings.Fullscreen;
	//cp.AntiAlias = 15;

	Device = createDeviceEx(cp);
	if(!Device)
		return false;
	Device->setEventReceiver(this);

	Device->getVideoDriver()->setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, true);
	Device->getSceneManager()->setAmbientLight(SColorf(1,1,1));

	array<SKeyMap> keymap;
	SKeyMap sk;
	sk.Action = EKA_MOVE_FORWARD;
	sk.KeyCode = KEY_KEY_W;
	keymap.push_back(sk);
	sk.Action = EKA_MOVE_BACKWARD;
	sk.KeyCode = KEY_KEY_S;
	keymap.push_back(sk);
	sk.Action = EKA_STRAFE_LEFT;
	sk.KeyCode = KEY_KEY_A;
	keymap.push_back(sk);
	sk.Action = EKA_STRAFE_RIGHT;
	sk.KeyCode = KEY_KEY_D;
	keymap.push_back(sk);
	sk.Action = EKA_JUMP_UP;
	sk.KeyCode = KEY_KEY_F;
	keymap.push_back(sk);

	Camera = Device->getSceneManager()->addCameraSceneNodeFPS(0, 50.0f, 0.002f, -1, keymap.pointer(), keymap.size(), false, 0.4f);
	Camera->setNearValue(0.1f);
	Camera->setFarValue(30);
	CameraAnimator = (ISceneNodeAnimatorCameraFPS*)*Camera->getAnimators().begin();

	return true;
}

void CDFize::createGui()
{
	IGUIEnvironment *gui = Device->getSceneManager()->getGUIEnvironment();
	IVideoDriver *video = Device->getVideoDriver();
	// Settings
	IGUIWindow *window = gui->addWindow(rect<s32>(0, 0, 125, 225), false, L"Settings");
	rect<s32> rc = window->getClientRect();

	IGUICheckBox *checkboxtiles = gui->addCheckBox(true, rect<s32>(rc.UpperLeftCorner.X, rc.UpperLeftCorner.Y, rc.LowerRightCorner.X, rc.UpperLeftCorner.Y + 20), window, 1, L"Show terrain & constructios");
	IGUICheckBox *checkboxcollision = gui->addCheckBox(false, rect<s32>(rc.UpperLeftCorner.X, rc.UpperLeftCorner.Y + 20, rc.LowerRightCorner.X, rc.UpperLeftCorner.Y + 40), window, 2, L"Show collision data");
	IGUICheckBox *checkboxwireframe = gui->addCheckBox(false, rect<s32>(rc.UpperLeftCorner.X, rc.UpperLeftCorner.Y + 40, rc.LowerRightCorner.X, rc.UpperLeftCorner.Y + 60), window, 3, L"Wireframe terrain");

	gui->addCheckBox(true, rect<s32>(rc.UpperLeftCorner.X, rc.UpperLeftCorner.Y + 70, rc.LowerRightCorner.X, rc.UpperLeftCorner.Y + 90), window, 4, L"Enable collision");
	gui->addCheckBox(false, rect<s32>(rc.UpperLeftCorner.X, rc.UpperLeftCorner.Y + 100, rc.LowerRightCorner.X, rc.UpperLeftCorner.Y + 120), window, 5, L"Highlight adjacent tiles");
	gui->addCheckBox(false, rect<s32>(rc.UpperLeftCorner.X, rc.UpperLeftCorner.Y + 120, rc.LowerRightCorner.X, rc.UpperLeftCorner.Y + 140), window, 6, L"Highlight corner tiles");
	gui->addCheckBox(true, rect<s32>(rc.UpperLeftCorner.X, rc.UpperLeftCorner.Y + 140, rc.LowerRightCorner.X, rc.UpperLeftCorner.Y + 160), window, 7, L"Use meshbuffer batching");

	gui->addStaticText(L"Draw distance", rect<s32>(rc.UpperLeftCorner.X, rc.UpperLeftCorner.Y + 170, rc.LowerRightCorner.X, rc.UpperLeftCorner.Y + 190), false, true, window);
	IGUIComboBox *combo = gui->addComboBox(rect<s32>(rc.UpperLeftCorner.X + 60, rc.UpperLeftCorner.Y + 165, rc.LowerRightCorner.X, rc.UpperLeftCorner.Y + 185), window, 8);
	combo->addItem(L"Near", 10);//50);
	combo->addItem(L"Middle", 30);//200);
	combo->addItem(L"Far", 70);//350);
	combo->addItem(L"Further", 200);//500);
	combo->setSelected(1);

	// Dwarves
	IGUIWindow *window2 = gui->addWindow(rect<s32>(0, 225, 125, 525), false, L"Dwarves");
	CreatureList = gui->addListBox(window2->getClientRect(), window2);

	// Info
	dimension2d<u32> screensize = video->getScreenSize();
	IGUIWindow *window3 = gui->addWindow(rect<s32>(screensize.Width - 125, 0, screensize.Width, 200), false, L"Info");
	rc = window3->getClientRect();
	GuiTileType = gui->addStaticText(L"Tile type", rect<s32>(rc.UpperLeftCorner.X, rc.UpperLeftCorner.Y + 10, rc.LowerRightCorner.X, rc.UpperLeftCorner.Y + 30), false, true, window3);
	GuiVegType = gui->addStaticText(L"Vegetation type", rect<s32>(rc.UpperLeftCorner.X, rc.UpperLeftCorner.Y + 30, rc.LowerRightCorner.X, rc.UpperLeftCorner.Y + 50), false, true, window3);
	GuiMaterial = gui->addStaticText(L"Material", rect<s32>(rc.UpperLeftCorner.X, rc.UpperLeftCorner.Y + 50, rc.LowerRightCorner.X, rc.UpperLeftCorner.Y + 70), false, true, window3);

	// HQ
	IGUIWindow *window4 = gui->addWindow(rect<s32>(screensize.Width - 125, 200, screensize.Width, 400), false, L"HQ");
	HqImage = gui->addImage(window4->getClientRect(), window4);

	HqTexture = video->addRenderTargetTexture(dimension2d<u32>(1024,768), "rt", video->getColorFormat());
}

bool CDFize::initDfHack()
{
	DFHack::ContextManager DFMgr("Memory.xml");
    try
    {
        DfHack = DFMgr.getSingleContext();
        DfHack->Attach();
    }
	catch (std::exception &ex)
    {
		log("DFHack", ex.what());
        return false;
    }
	log("DFHack", "Initialized");
	return true;
}

/*SNode* CDFize::getCreature(u32 index) const
{
	if(index < Creatures.size())
		return Creatures[index];
	return 0;
}*/